package com.dji.ux.sample.RTCSignalClient;

import android.util.Log;

import com.dji.ux.sample.CompleteWidgetActivity;
import com.dji.ux.sample.VirtualSticks.VirtualSticksController;

import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.handshake.ServerHandshake;
import org.json.JSONException;
import org.json.JSONObject;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Timer;
import java.util.TimerTask;


public class RTCSignalClient {

    private static final String TAG = "RTCSignalClient";
    private static final String WS_URL = "ws://"+CompleteWidgetActivity.localIp+":3000";

    // join 主动加入房间
    // leave 主动离开房间
    // new-peer 有人加入房间，通知已经在房间的人
    // peer-leave 有人离开房间，通知已经在房间的人
    // offer 发送offer给对端peer
    // answer发送offer给对端peer
    // candidate 发送candidate给对端peer
    public static final String SIGNAL_TYPE_JOIN = "join";
    public static final String SIGNAL_TYPE_RESP_JOIN = "resp-join";  // 告知加入者对方是谁
    public static final String SIGNAL_TYPE_LEAVE = "leave";
    public static final String SIGNAL_TYPE_NEW_PEER = "new-peer";
    public static final String SIGNAL_TYPE_PEER_LEAVE = "peer-leave";
    public static final String SIGNAL_TYPE_OFFER = "offer";
    public static final String SIGNAL_TYPE_ANSWER = "answer";
    public static final String SIGNAL_TYPE_CANDIDATE = "candidate";
    public static final String SIGNAL_TYPE_FLIGHTDATA = "flightdata";
    public static final String SIGNAL_TYPE_CONTROLDATA = "controldata";
    public static final String SIGNAL_TYPE_WAYPOINTDATA = "waypointdata";
    public static final String SIGNAL_TYPE_STARTWAYPOINT = "startwaypoint";
    public static final String SIGNAL_TYPE_PLCDATA = "plcdata";
    public static final String SIGNAL_TYPE_TACKOFF = "takeoff";
    public static final String SIGNAL_TYPE_LAND = "land";

    public static final String SIGNAL_TYPE_MISSIONSTATE = "missionstate";
    public static final String SIGNAL_TYPE_GIMBALDATA = "gimbaldata";
    public static final String SIGNAL_TYPE_VIRTUALSTICKDATA = "virtualstickdata";
    public static final String SIGNAL_TYPE_VIRTUALSTICKSWITCH = "virtualstickswitch";
    public static final String SIGNAL_TYPE_MECDATA = "mecdata";
    public static final String SIGNAL_TYPE_WEB_MULTLIVE = "web-mult-live";
    public static final String SIGNAL_TYPE_WEB_MULTLIVE_LEAVE = "web-mult-live-leave";
    public static final String SIGNAL_TYPE_LANDINSPECTIONWAYPOINT = "landinspectionwaypoint";
    public static final String SIGNAL_TYPE_HEARTBEAT = "heartbeat";


    private OnSignalEventListener mOnSignalEventListener;

    private WebSocketClient mWebSocketClient;
    private String mUserId;
    private String mRoomId;

    private final static int MAX_NUM = 500;       // 最大重连数
    private int connectNum = 0;

    private boolean isConnect = false;

    public RTCSignalClient(final OnSignalEventListener listener) {
        URI uri = null;
        try {
            uri = new URI(WS_URL);
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
        mOnSignalEventListener = listener;// 设置回调函数
        mWebSocketClient = new JWebSocketClient(uri);   // 新建websocket类
        mOnSignalEventListener.onConnecting();  // 通知应用层正在连接信令服务器

        mWebSocketClient.connect(); // 去连接信令服务器
        Log.i(TAG, "RTCSignalClient");
    }

    public class JWebSocketClient extends WebSocketClient {

        public JWebSocketClient(URI serverUri) {
            super(serverUri, new Draft_6455());
        }

        /**
         * 重连
         */
        public void reconnect() {
            if (connectNum <= MAX_NUM) {
                try {
                    Thread.sleep(3000);
                    mOnSignalEventListener.onReconnecting();  // 通知应用层正在重新连接信令服务器
                    mWebSocketClient.connect(); // 去连接信令服务器
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } else {
                Log.i(TAG, "reconnect over " + MAX_NUM + ",please check url or network");
            }
        }

        @Override
        public void onOpen(ServerHandshake handshakedata) { // 说明websocket连接成功
            Log.i(TAG, "onOpen()");
            if (mOnSignalEventListener != null) {
                mOnSignalEventListener.onConnected();
                isConnect = true;
            }
            /**
             * 间隔5秒发送一次websocket心跳包
             */
            new Thread(() -> {
                Timer timer = new Timer();
                timer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        sendHeartBeat();
                    }
                }, 0, 5 * 1000);
            }).start();
        }

        @Override
        public void onMessage(String message) { // 接收服务器发送过来的数据
            Log.i(TAG, "onMessage()" + message);
            if (mOnSignalEventListener != null) {
                try {
                    JSONObject jsonMsg = new JSONObject(message);
                    String cmd = jsonMsg.getString("cmd");
                    switch (cmd) {
                        case SIGNAL_TYPE_NEW_PEER:
                            mOnSignalEventListener.onRemoteNewPeer(jsonMsg);
                            break;
                        case SIGNAL_TYPE_RESP_JOIN:
                            mOnSignalEventListener.onResponseJoin(jsonMsg);
                            break;
                        case SIGNAL_TYPE_PEER_LEAVE:
                            mOnSignalEventListener.onRemotePeerLeave(jsonMsg);
                            break;
                        case SIGNAL_TYPE_OFFER:
                            mOnSignalEventListener.onRemoteOffer(jsonMsg);
                            break;
                        case SIGNAL_TYPE_ANSWER:
                            mOnSignalEventListener.onRemoteAnswer(jsonMsg);
                            break;
                        case SIGNAL_TYPE_CANDIDATE:
                            mOnSignalEventListener.onRemoteCandidate(jsonMsg);
                            break;
                        case SIGNAL_TYPE_CONTROLDATA:
                            mOnSignalEventListener.onControlDataRcv(jsonMsg);
                            break;
                        case SIGNAL_TYPE_WAYPOINTDATA:
                            mOnSignalEventListener.onWaypointDataRcv(jsonMsg);
                            break;
                        case SIGNAL_TYPE_LANDINSPECTIONWAYPOINT:
                            mOnSignalEventListener.onLandInspectionRcv(jsonMsg);
                            break;
                        case SIGNAL_TYPE_STARTWAYPOINT:
                            mOnSignalEventListener.onStartWaypoint(jsonMsg);
                            break;
                        case SIGNAL_TYPE_PLCDATA:
                            mOnSignalEventListener.onPlcDataRcv(jsonMsg);
                            break;
                        case SIGNAL_TYPE_TACKOFF:
                            mOnSignalEventListener.onTakeOffRcv(jsonMsg);
                            break;
                        case SIGNAL_TYPE_LAND:
                            mOnSignalEventListener.onLandRcv(jsonMsg);
                            break;
                        case SIGNAL_TYPE_GIMBALDATA:
                            mOnSignalEventListener.onGimbalDataRcv(jsonMsg);
                            break;
                        case SIGNAL_TYPE_MISSIONSTATE:
                            mOnSignalEventListener.onMissionStateRcv(jsonMsg);
                            break;
                        case SIGNAL_TYPE_VIRTUALSTICKDATA:
                            mOnSignalEventListener.onVirtualStickDataRcv(jsonMsg);
                            break;
                        case SIGNAL_TYPE_VIRTUALSTICKSWITCH:
                            mOnSignalEventListener.onVirtualStickSwitchRcv(jsonMsg);
                            break;
                        case SIGNAL_TYPE_MECDATA://multi access edge calculator
                            mOnSignalEventListener.onMECDataRcv(jsonMsg);
                            break;
                        case SIGNAL_TYPE_WEB_MULTLIVE:
                            mOnSignalEventListener.onMultLive(jsonMsg);
                            break;
                        case SIGNAL_TYPE_WEB_MULTLIVE_LEAVE:
                            mOnSignalEventListener.onMultLiveLeave(jsonMsg);
                            break;
                        default:
                            Log.e(TAG, "can't handle the cmd " + cmd);
                            break;
                    }
                } catch (JSONException e) {
                    Log.e(TAG, "WebSocket message JSON parsing error: " + e.toString());
                }
            }
        }

        @Override
        public void onClose(int code, String reason, boolean remote) {
            Log.w(TAG, "onClose() reason:" + reason + ", clode:" + code);
            if (mOnSignalEventListener != null) {
                mOnSignalEventListener.onClosse();
                isConnect = false;
                reconnect();
            }
        }

        @Override
        public void onError(Exception ex) {
            Log.e(TAG, "onError()" + ex);
            if (mOnSignalEventListener != null) {
                mOnSignalEventListener.onDisconnected();
                isConnect = false;
//                reconnect();
            }
        }
    }

    public interface OnSignalEventListener {
        void onConnected();

        void onConnecting();

        void onJoinRoomFailure();

        void onReconnecting();

        void onDisconnected();

        void onClosse();

        void onRemoteNewPeer(JSONObject message);   // 新人加入

        void onResponseJoin(JSONObject message);    // 加入回应

        void onRemotePeerLeave(JSONObject message);

        void onRemoteOffer(JSONObject message);

        void onRemoteAnswer(JSONObject message);

        void onRemoteCandidate(JSONObject message);

        void onControlDataRcv(JSONObject message);

        //无人机管理平台航点任务接口
        void onWaypointDataRcv(JSONObject message);

        //国土查违航点任务接口
        void onLandInspectionRcv(JSONObject message);

        void onStartWaypoint(JSONObject message);

        void onPlcDataRcv(JSONObject message);

        void onTakeOffRcv(JSONObject message);

        void onLandRcv(JSONObject message);

        void onGimbalDataRcv(JSONObject message);

        void onMissionStateRcv(JSONObject message);

        void onVirtualStickDataRcv(JSONObject message);

        void onVirtualStickSwitchRcv(JSONObject message);

        void onMECDataRcv(JSONObject message);

        void onMultLive(JSONObject message);

        void onMultLiveLeave(JSONObject message);
    }

    public String getUserId() {
        return mUserId;
    }

    public boolean isConnect() {
        return isConnect;
    }

    public void joinRoom(String userId, String roomId) {
        Log.i(TAG, "joinRoom: " + userId + ", " + roomId);
        if (mWebSocketClient == null) {
            mOnSignalEventListener.onJoinRoomFailure();
            return;
        }
        mUserId = userId;
        mRoomId = roomId;
        try {
            JSONObject args = new JSONObject();
            args.put("cmd", SIGNAL_TYPE_JOIN);
            args.put("roomId", mRoomId);
            args.put("uid", mUserId);
            if (isConnect) mWebSocketClient.send(args.toString());
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    public void sendMECSignal(String userId, String roomId, String recordName, int urSwitch, int urPosition) {
        Log.i(TAG, "sendMECSignal: " + userId + ", " + roomId);
        if (mWebSocketClient == null) {
            return;
        }
        mUserId = userId;
        mRoomId = roomId;
        try {
            JSONObject args = new JSONObject();
            args.put("cmd", SIGNAL_TYPE_MECDATA);
            args.put("roomId", mRoomId);
            args.put("uid", mUserId);
            args.put("remoteRoomId", "MEC");
            args.put("remoteUid", "MecClient");
            args.put("recordName", recordName);
            args.put("urlandSwitch", urSwitch);
            args.put("urlandPosition", urPosition);
            if (urSwitch == 1) VirtualSticksController.readyAlternating = true;
            if (isConnect) mWebSocketClient.send(args.toString());
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    public void sendHeartBeat() {
        Log.i(TAG, "sendHeartBeat");
        if (mWebSocketClient == null) return;
        try {
            JSONObject args = new JSONObject();
            args.put("cmd", SIGNAL_TYPE_HEARTBEAT);
            if (isConnect) mWebSocketClient.send(args.toString());
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    public void sendMECSignal2(String userId, String roomId, String recordName, String missionType) {
        Log.i(TAG, "sendMECSignal: " + userId + ", " + roomId);
        if (mWebSocketClient == null) {
            return;
        }
        mUserId = userId;
        mRoomId = roomId;
        try {
            JSONObject args = new JSONObject();
            args.put("cmd", SIGNAL_TYPE_MECDATA);
            args.put("roomId", mRoomId);
            args.put("uid", mUserId);
            args.put("remoteRoomId", "MEC");
            args.put("remoteUid", "MecClient");
            args.put("recordName", recordName);
            args.put("missionType", missionType);
            if (isConnect) mWebSocketClient.send(args.toString());
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    public void leaveRoom() {
        Log.i(TAG, "leaveRoom: " + mRoomId);
        if (mWebSocketClient == null) {
            return;
        }
        try {
            JSONObject args = new JSONObject();
            args.put("cmd", SIGNAL_TYPE_LEAVE);
            args.put("roomId", mRoomId);
            args.put("uid", mUserId);
            if (isConnect) mWebSocketClient.send(args.toString());
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    public void sendOffer(String offer, String remoteUid) {
        Log.i(TAG, "send offer");
        if (mWebSocketClient == null) {
            return;
        }
        try {
            JSONObject args = new JSONObject();
            args.put("cmd", SIGNAL_TYPE_OFFER);
            args.put("roomId", mRoomId);
            args.put("uid", mUserId);
            args.put("remoteUid", remoteUid);
            args.put("msg", offer);
            if (isConnect) mWebSocketClient.send(args.toString());
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    public void sendAnswer(String answer, String remoteUid) {
        Log.i(TAG, "send answer");
        if (mWebSocketClient == null) {
            return;
        }
        try {
            JSONObject args = new JSONObject();
            args.put("cmd", SIGNAL_TYPE_ANSWER);
            args.put("roomId", mRoomId);
            args.put("uid", mUserId);
            args.put("remoteUid", remoteUid);
            args.put("msg", answer);
            if (isConnect) mWebSocketClient.send(args.toString());
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    public void sendCandidate(String candidate, String remoteUid) {
//        Log.i(TAG, "send candidate");
        if (mWebSocketClient == null) {
            return;
        }
        try {
            JSONObject args = new JSONObject();
            args.put("cmd", SIGNAL_TYPE_CANDIDATE);
            args.put("roomId", mRoomId);
            args.put("uid", mUserId);
            args.put("remoteUid", remoteUid);
            args.put("msg", candidate);
            if (isConnect) mWebSocketClient.send(args.toString());
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    public void sendFlightdata(String flightData, String remoteUid) {
        if (mWebSocketClient == null) {
            return;
        }
        try {
            JSONObject args = new JSONObject();
            args.put("cmd", SIGNAL_TYPE_FLIGHTDATA);
            args.put("roomId", mRoomId);
            args.put("uid", mUserId);
            args.put("remoteUid", remoteUid);
            args.put("msg", flightData);
            if (isConnect) mWebSocketClient.send(args.toString());
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }


    public void disConnect() {
        if (mWebSocketClient == null) {
            return;
        }
        mWebSocketClient.close();
        mWebSocketClient = null;
    }
}
